// Scanner.java -- the implementation of class Scanner

import java.io.*;

class Scanner {
	private PushbackInputStream in;
	private byte[] buf = new byte[1000];

	public Scanner(InputStream i) {
		in = new PushbackInputStream(i);
	}

	public Token getNextToken() 
	{
		int bite = -1;

		// It would be more efficient if we'd maintain our own input buffer
		// and read characters out of that buffer, but reading individual
		// characters from the input stream is easier.

		try {
			bite = in.read();
		} catch (IOException e) {
			System.err.println("We fail: " + e.getMessage());
		}

		// TODO: skip white space and comments

		if (bite == -1)
			return null;

		char ch = (char) bite;

		if (ch == '\t')
			return getNextToken();
		else if (ch == '\n')
			return getNextToken();

		if (ch == ' ')
			getNextToken();

		if (ch == ';')
			while (bite != -1) {
				try {
					bite = in.read();
				} catch (IOException e) {
					e.printStackTrace();
				}
			}

		// Special characters
		if (ch == '\'')
			return new Token(Token.QUOTE);
		else if (ch == '(')
			return new Token(Token.LPAREN);
		else if (ch == ')')
			return new Token(Token.RPAREN);
		else if (ch == '.')
			// We ignore the special identifier `...'.
			return new Token(Token.DOT);

		// Boolean constants
		else if (ch == '#') {
			try {
				bite = in.read();
			} catch (IOException e) {
				System.err.println("We fail: " + e.getMessage());
			}

			if (bite == -1) {
				System.err.println("Unexpected EOF following #");
				return null;
			}
			ch = (char) bite;
			if (ch == 't')
				return new Token(Token.TRUE);
			else if (ch == 'f')
				return new Token(Token.FALSE);
			else {
				System.err.println("Illegal character '" + (char) ch
						+ "' following #");
				return getNextToken();
			}
		}

		// String constants
		else if (ch == '"') 
		{
			// TODO: scan a string into the buffer variable buf
			try
			{
			bite = in.read();
			

			int count = 0;
			ch = (char) bite;
			while (bite != -1 && ch != '"')
			{
				try {
					// ch = (char) in.read(buf);
					//int count = 0;
					buf [count] = (byte) bite;
					ch = (char) bite;
					bite = in.read();
					count ++;
					
				   } catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
			
			/*
			 * bite = in.read(); while (bite != -1) { char ch2 = (char) bite;
			 * buf = ch2; }
			 */
			}catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			return new StrToken(buf.toString());
			}
		}

		// Integer constants
		else if (ch >= '0' && ch <= '9') 
		{
			int i = ch - '0';
			
			try {
				bite = in.read();
				while (bite != 1 && ch >= '0' && ch <= '9') 
				{
					ch = (char) bite;
					bite = in.read();
				}
				} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				}
			try
			{
				in.unread(ch);
			}catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();}
			// TODO: scan the number and convert it to an integer
			// put the character after the integer back into the input
			// in->putback(ch);
			return new IntToken(i);
		}

		// Identifiers
		else if (ch >= 'A' && ch <= 'Z'
		/* or ch is some other valid first character for an identifier */) 
		{
			int count = 0;
			// TODO: scan an identifier into the buffer 
      
			while(ch != '\n' && ch != ')' && ch != (char)20 && ch != (char)32)
			{  
				buf[count] = (byte)ch;  
				count++;
		
				try
				{
					ch = (char)in.read();
				}
				catch(IOException e)
				{
					System.err.println("System Error: " + e.getMessage());
				}
			}
	  	  
			try
			{
    			in.unread(ch);
			}
			catch(IOException e)
			{
				System.err.println("System Error: " + e.getMessage());
			}
			// TODO: scan an identifier into the buffer

			// put the character after the identifier back into the input
			// in->putback(ch);
			return new IdentToken(buf.toString());
		}

		// Illegal character
		else {
			System.err.println("Illegal input character '" + (char) ch + '\'');
			return getNextToken();
		}
		return getNextToken();
	};
}
